package fr.inserm.u915.tabixserver;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.picard.reference.IndexedFastaSequenceFile;
import net.sf.picard.reference.ReferenceSequence;
import net.sf.picard.reference.ReferenceSequenceFile;
import net.sf.picard.reference.ReferenceSequenceFileWalker;

import fr.inserm.u915.tabixserver.segparser.SegmentParser;

public class FastaServlet extends HttpServlet
	{
	private static abstract class AbstractFastaHandler implements FastaHandler
		{
		Build build;
		int nseq=0;
		long sequence_size=0L;
		protected PrintWriter out;
		AbstractFastaHandler(Build build,PrintWriter out)
			{
			this.build=build;
			this.out=out;
			}
		@Override
		public void startDocument() throws IOException {
			
			}
		@Override
		public void endDocument() throws IOException {
			out.flush();
			}
		}
	
	private static class PaintTextFastaHandler extends AbstractFastaHandler
		{
		PaintTextFastaHandler(Build build,PrintWriter out)
			{
			super(build,out);
			}
		
		@Override
		public String getContentType()
			{
			return "text/plain";
			}

		@Override
		public void startQuery(String chrom, int start, int end)
				throws IOException
			{
			if(nseq>0) out.println();
			sequence_size=0;
			nseq=0;
			out.print(">("+build.getId()+")"+chrom+":"+start+"-"+end);
			}
		
		@Override
		public void characters(byte[] array) throws IOException
			{
			for(int i=0;i< array.length;++i)
				{
				if(sequence_size%50==0)
					{
					out.println();
					}
				out.print((char)array[i]);
				++sequence_size;
				}
			}
		
		@Override
		public void endQuery() throws IOException {
			out.println();
			}
		}
	
	
	
	private static final long serialVersionUID = 1L;
	@SuppressWarnings("unchecked")
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException
		{
		final Model model=(Model)this.getServletContext().getAttribute(TabixCtxListener.TABIX_MODEL_ATTRIBUTE);
		if(model==null) throw new ServletException("model?");
	
		String query=req.getParameter("q");
		if(query==null) throw new ServletException("no query");
		
		Build build=(Build)req.getAttribute("build");
		if(build==null) throw new ServletException("build?");
		
		File fastaFile=build.getFastaFile();
		if(fastaFile==null)
			{
			throw new ServletException("No fasta file defined for build id "+build);
			}
		
		List<Segment> segs=(List<Segment>)req.getAttribute("segments");
		if(segs==null) throw new ServletException("segs?");
		
		PrintWriter out=null;
		IndexedFastaSequenceFile faidx=null;
		try
			{
			faidx=new IndexedFastaSequenceFile(fastaFile);
			out=resp.getWriter();
			FastaHandler fastaHandler= new PaintTextFastaHandler(build,out);
			 
			resp.setContentType(fastaHandler.getContentType());
			fastaHandler.startDocument();
		    
			
			for(Segment seg:segs)
				{ 
				fastaHandler.startQuery(seg.getChromosome(),seg.getStart(),seg.getEnd());
				int start=seg.getStart();
				
				while(start<seg.getEnd())
					{
					int end=Math.min(start+10000, seg.getEnd());
					ReferenceSequence ref=faidx.getSubsequenceAt(seg.getChromosome(), start, end);
					byte bases[]=ref.getBases();
					fastaHandler.characters(bases);
					start+=bases.length;
					}
				
				fastaHandler.endQuery();
				}
			fastaHandler.endDocument();
			}
		catch(Exception err)
			{
			throw new ServletException(err);
			}
		finally
			{
			if(out!=null)
				{
				out.flush();
				out.close();
				}
			}
		}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		doPost(req, resp);
		}
}
